﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace MyCollection
{
    class MyIListRealization : IList, IDisposable
    {
        #region Constructor

        public MyIListRealization(IEnumerable<MyKeyValuePair> values, int count)
        {
            m_values = (MyKeyValuePair[])Array.CreateInstance(typeof(MyKeyValuePair), count);

            int index = -1;

            foreach (var item in values)
            {
                index++;

                if (index > count)
                    break;

                m_values.SetValue(item, index);
            }

            m_count = index - 1;
        }

        #endregion

        #region IList implemintation
        /// <summary>
        /// +++
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public int Add(object value)
        {
            Insert(m_count, value);

            return 1;
        }

        /// <summary>
        /// +++
        /// </summary>
        public void Clear()
        {
            m_count = 0;
        }

        /// <summary>
        /// +++
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Contains(object value)
        {
            bool isPresent = false;

            if (IndexOf(value) > 0)
            {
                isPresent = true;
            }

            return isPresent;
        }

        /// <summary>
        /// +++
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public int IndexOf(object value)
        {
            int result = -1;

            for (int i = 0; i < m_count; i++)
            {
                if (m_values.GetValue(i) == value)
                {
                    result = i;
                    break;
                }
            }

            return result;
        }

        /// <summary>
        /// ++++
        /// </summary>
        /// <param name="index"></param>
        /// <param name="value"></param>
        public void Insert(int index, object value)
        {
            if (index < 0 || index > m_count)
                throw new ArgumentOutOfRangeException();

            MyKeyValuePair[] temp = (MyKeyValuePair[])Array.CreateInstance(typeof(MyKeyValuePair), m_count + 1);

            if (index == m_count)
            {
                InsertTempMas(ref temp, 0, m_count, 0);                
            }
            else
            {
                InsertTempMas(ref temp, 0, index, 0);
                InsertTempMas(ref temp, index, m_count - index, 1);
            }

            temp.SetValue(value, index);

            m_values = temp;
            m_count++;
        }

        private void InsertTempMas(ref MyKeyValuePair[] temp, int pos, int count, int dif)
        {
            for (int i = pos; i < pos + count; i++)
            {
                temp.SetValue(m_values[i], i + dif);
            }
        }

        /// <summary>
        /// ++++
        /// </summary>
        public bool IsFixedSize
        {
            get { return true; }
        }

        /// <summary>
        /// ++++
        /// </summary>
        public bool IsReadOnly
        {
            get { return false; }
        }

        /// <summary>
        /// ++++
        /// </summary>
        /// <param name="value"></param>
        public void Remove(object value)
        {
            int isPresent = IndexOf(value);

            if (isPresent > 0)
            {
                RemoveAt(isPresent);
            }
        }

        /// <summary>
        /// ++++
        /// </summary>
        /// <param name="index"></param>       
        public void RemoveAt(int index)
        {
            if (index < 0 || index >= m_count)
                throw new ArgumentOutOfRangeException();

            for (int i = index; i < m_count; i++)
            {
                m_values.SetValue(m_values[i + 1], i);
            }

            m_count--;
        }

        /// <summary>
        /// ++++
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public object this[int index]
        {
            get
            {
                return m_values.GetValue(index);
            }
            set
            {
                m_values.SetValue(value, index);
            }
        }

        /// <summary>
        /// ++++
        /// </summary>
        /// <param name="array"></param>
        /// <param name="index"></param>
        public void CopyTo(Array array, int index)
        {
            if (array == null)
                throw new ArgumentNullException();

            if (index < 0)
                throw new ArgumentOutOfRangeException();

            if (array.Length - index < m_count)
                throw new ArgumentException("array");

            for (int i = index; i < m_count; i++)
            {
                array.SetValue(m_values[i], index + i);
            }
        }

        /// <summary>
        /// ++++
        /// </summary>
        public int Count
        {
            get { return m_count; }
        }

        /// <summary>
        /// ++++
        /// </summary>
        public bool IsSynchronized
        {
            get { return false; }
        }

        /// <summary>
        /// +++
        /// </summary>
        public object SyncRoot
        {
            get { return __mutex; }
        }

        public IEnumerator GetEnumerator()
        {
            throw new NotImplementedException();
        }

        #endregion
        
        #region Private fields

        /// <remarks>
        /// After add and remove operations m_count must
        /// change value but it's read only field
        /// </remarks>
        private int m_count = 0;

        /// <remarks>
        /// After add and remove operations size m_values must
        /// change value but it's read only field
        /// </remarks>
        private MyKeyValuePair[] m_values = null;

        private readonly object __mutex = new object();

        #endregion

        #region IDisposable implemintation

	~MyIListRealization()
        {
	    Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool isDisposed)
        {
            if (m_IsDisposed)
                return;

            try { }
            catch(Exception)
            {
                throw;
            }

            if (isDisposed)
            { }

            m_IsDisposed = true;
        }

        private bool m_IsDisposed = false;
        #endregion
    }
}
